using UnityEngine;

public class Trigger : MonoBehaviour
{

    public Transform targetObject;
    private bool m_staying;

    public TriggerInvokable Invokable
    {
        get => this.invokable;
        set
        {
            invokable = value;
            UpdateTriggerReference();
        }
    }
    
    [SerializeField] private TriggerInvokable invokable;
    private bool m_triggered;

    public void Update()
    {
        if (!targetObject || !Invokable) return;
        if (m_triggered != m_staying)
        {
            if (m_triggered)
            {
                invokable.TriggerEnter();
            }
            else
            {
                invokable.TriggerExit();
            }

            m_staying = m_triggered;
        }
        else if (m_staying)
        {
            invokable.TriggerStay();
        }
    }

    private void Awake()
    {
        m_triggered = false;
    }

    private void OnTriggerEnter(Collider other)
    {
        if (other.transform == targetObject)
        {
            m_triggered = true;
        }
    }

    private void OnTriggerExit(Collider other)
    {
        if (other.transform == targetObject)
        {
            m_triggered = false;
        }
    }

#if UNITY_EDITOR
    private void Reset()
    {
        if (GetComponents<Trigger>().Length > 1)
        {
            DestroyImmediate(this);
        }

        var line = FindObjectOfType<MainLine>();
        if (line)
        {
            targetObject = line.transform;
        }

        var invokable = GetComponent<TriggerInvokable>();
        if (invokable)
        {
            this.invokable = invokable;
        }
    }
#endif

    public void ResetState()
    {
        m_triggered = false;
    }

    public static void UpdateTriggerReference()
    {
        foreach (TriggerInvokable triggerInvokable in FindObjectsOfType<TriggerInvokable>())
        {
            triggerInvokable.trigger = null;
        }

        foreach (Trigger trigger in FindObjectsOfType<Trigger>())
        {
            if (!trigger.invokable) continue;
            trigger.invokable.trigger = trigger;
        }
    }
}

public abstract class TriggerInvokable : MonoBehaviour
{
    public Trigger trigger;
    public abstract void TriggerEnter();
    public abstract void TriggerExit();
    public abstract void TriggerStay();
}